using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.PeerResolvers;
using System.Threading;
using RPGOnline.Remoting.Entities;
using RPGOnline.Remoting.Events;

namespace RPGOnline.Remoting
{
    public class ChatManager : IChatCallback
    {
        private DuplexChannelFactory<IChat> m_factory;
        private InstanceContext m_callbackInstanceType;
        private IChat m_channel;
        private IOnlineStatus m_onlineStatus;
	    private Timer m_keepAliveTimer;

	    public event EventHandler OnRegistrationFailed;
        public event EventHandler OnRegistrationCompleted;
        public event EventHandler<MessageReceivedEventArgs> OnMessageReceived;
        public event EventHandler<PrivateMessageReceivedEventArgs> OnPrivateMessageReceived;
        public event EventHandler<UserRegistrationEventArgs> OnUserRegistered;
        public event EventHandler<UserRegistrationEventArgs> OnUserUnregistered;
        public event EventHandler<UserRollEventArgs> OnUserRolled;
        public event EventHandler<UserInfoChangedEventArgs> OnUserInfoChanged;
        public event EventHandler<GroupAddedEventArgs> OnGroupAdded;
        public event EventHandler<UserMovedToGroupEventArgs> OnUserMovedToGroup;
        public event EventHandler<SessionUpdatedEventArgs> OnSessionUpdated;

        public ChatManager(string serverIp, int serverPort)
        {
            m_callbackInstanceType = new InstanceContext(this);
            
            NetTcpBinding binding = new NetTcpBinding();
            binding.ReceiveTimeout = TimeSpan.MaxValue;
            binding.ReliableSession.Enabled = true;
            binding.ReliableSession.InactivityTimeout = TimeSpan.MaxValue;
            binding.ReliableSession.Ordered = true;
            binding.Security.Mode = SecurityMode.None;

            ContractDescription contractDescription = ContractDescription.GetContract(typeof (IChat));
            ServiceEndpoint serviceEndpoint = new ServiceEndpoint(contractDescription, binding, new EndpointAddress(string.Format("net.tcp://{0}:{1}/ChatServer/Service", serverIp, serverPort)));

            m_factory = new DuplexChannelFactory<IChat>(m_callbackInstanceType, serviceEndpoint);
            m_channel = m_factory.CreateChannel();
			
			m_keepAliveTimer = new Timer(state => m_channel.KeepAlive(), null, new TimeSpan(0, 0, 0, 10), new TimeSpan(0, 0, 0, 10));
        }

        public IChat Notify { get { return m_channel; } }
        
        public void RegistrationCompleted()
        {
            if (OnRegistrationCompleted != null)
                OnRegistrationCompleted(this, EventArgs.Empty);
        }

        public void RegistrationFailed()
        {
            if (OnRegistrationFailed != null)
                OnRegistrationFailed(this, EventArgs.Empty);
        }

        public void NewUserConnected(User user)
        {
            if(OnUserRegistered != null)
                OnUserRegistered(this, new UserRegistrationEventArgs(user, Guid.Empty));
        }

        public void UserDisconnected(User user)
        {
            if(OnUserUnregistered != null)
                OnUserUnregistered(this, new UserRegistrationEventArgs(user, Guid.Empty));
        }

        public void MessageReceived(User user, Guid chatGroupId, string message)
        {
            if(OnMessageReceived != null)
                OnMessageReceived(this, new MessageReceivedEventArgs(chatGroupId, user, message));
        }

        public void UpdatedSession(SessionContext sessionContext)
        {
            if(OnSessionUpdated != null)
                OnSessionUpdated(this, new SessionUpdatedEventArgs(sessionContext));
        }

        public void PrivateMessageReceived(User senderUser, User destinationUser, string message)
        {
            if(OnPrivateMessageReceived != null)
                OnPrivateMessageReceived(this, new PrivateMessageReceivedEventArgs(senderUser, destinationUser, message));
        }

        public void NewGroupCreated(ChatGroup chatGroup)
        {
            if(OnGroupAdded != null)
                OnGroupAdded(this, new GroupAddedEventArgs(chatGroup));
        }

        public void UserMovedToGroup(User user, Guid groupId)
        {
            if(OnUserMovedToGroup != null)
                OnUserMovedToGroup(this, new UserMovedToGroupEventArgs(user, groupId));
        }

        public void UserRolled(User user, RollResult rollResult)
        {
            if (OnUserRolled != null)
                OnUserRolled(this, new UserRollEventArgs(user, rollResult));
        }

        public void UserInfoChanged(User user)
        {
            if(OnUserInfoChanged != null)
                OnUserInfoChanged(this, new UserInfoChangedEventArgs(user));
        }
    }
}